﻿using ConverterSystems.ServiceModel;
using Opc.Ua;
using Opc.Ua.Client;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Security;

namespace ConverterSystems.TestLogger
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            // Step 1 - Create a config.  These settings will generate a certificate if neccessary.
            var config = new ApplicationConfiguration()
            {
                ApplicationName = "ConverterSystems.TestLogger",
                ApplicationType = ApplicationType.Client,
                SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier { StoreType = @"Windows", StorePath = @"CurrentUser\My", SubjectName = Utils.Format(@"CN={0}, DC={1}", "ConverterSystems.TestLogger", System.Net.Dns.GetHostName()) }, TrustedPeerCertificates = new CertificateTrustList { StoreType = @"Windows", StorePath = @"CurrentUser\TrustedPeople", }, NonceLength = 32, AutoAcceptUntrustedCertificates = true },
                TransportConfigurations = new TransportConfigurationCollection(),
                TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
                ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }
            };
            config.Validate(ApplicationType.Client);
            config.EnsureApplicationCertificate();
            if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
            {
                config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); };
                ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return (d == SslPolicyErrors.None) || (d == SslPolicyErrors.RemoteCertificateChainErrors); };
            }

            // Step 2 - Create a session with your server.
            using (var session = new UaSession(config, "opc.tcp://" + Dns.GetHostName() + ":51212"))
            {
                // Step 3 - Create a subscription. Choose faster publishing interval if you wish.
                var subscription = new Subscription(session.DefaultSubscription) { PublishingInterval = 1000 };

                // Step 4 - Create a list of items you wish to monitor
                var list = new List<MonitoredItem> {
                new MonitoredItem(subscription.DefaultItem){DisplayName="ServerStatusCurrentTime", StartNodeId="i=2258"},
                new MonitoredItem(subscription.DefaultItem){DisplayName="Robot1Axis1", StartNodeId="ns=2;s=Robot1_Axis1"},
                new MonitoredItem(subscription.DefaultItem){DisplayName="Robot1Axis2", StartNodeId="ns=2;s=Robot1_Axis2"},
                new MonitoredItem(subscription.DefaultItem){DisplayName="Robot1Axis3", StartNodeId="ns=2;s=Robot1_Axis3"},
                new MonitoredItem(subscription.DefaultItem){DisplayName="Robot1Axis4", StartNodeId="ns=2;s=Robot1_Axis4"},
                new MonitoredItem(subscription.DefaultItem){DisplayName="Robot1Mode", StartNodeId="ns=2;s=Robot1_Mode"},
                new MonitoredItem(subscription.DefaultItem){DisplayName="Robot1Speed", StartNodeId="ns=2;s=Robot1_Speed"},
                new MonitoredItem(subscription.DefaultItem){DisplayName="Robot1Laser", StartNodeId="ns=2;s=Robot1_Laser"}
                };
                list.ForEach(i => i.Notification += OnNotification);

                // Step 5 - Add the list to the subscription.
                subscription.AddItems(list);

                // Step 6 - Add the subscription to the session.
                session.AddSubscription(subscription);
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey(true);
            }
        }

        private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
        {
            foreach (var value in item.DequeueValues())
            {
                // Step 7 - Add your logging code here.
                Console.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
            }
        }
    }
}